package com.bdv.md.job;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Timestamp;
import java.util.Date;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;

import com.bdv.md.controller.xmlattribute.Parameter;
import com.bdv.md.controller.xmlattribute.TlkmTsel;
import com.bdv.md.en.ConstantValues;
import com.bdv.md.en.HTTPValues;
import com.bdv.md.en.UrlList;
import com.bdv.md.model.MapTbl;
import com.bdv.md.service.TransactionService;

public class MeterReadingJob implements Job  {
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	@Autowired(required = true)
	private TransactionService trxSvc;
	
	public void execute(JobExecutionContext jec) throws JobExecutionException {
		SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 
		
		MapTbl mapTbl = (MapTbl)jec.getJobDetail().getJobDataMap().get("mapTbl");
		System.out.println("SERVICE: "+trxSvc);
		String trxId = trxSvc.validTxIdWithS(4);
		
		String url = UrlList.USSD_AMR_REQUEST.getUrl();
		Parameter param = new Parameter(trxId, ConstantValues.NO_AKSES.getCode().toString(), mapTbl.getTipePu().toString(), mapTbl.getMsisdn(), mapTbl.getMeterId());
		param.setUtilityCode(ConstantValues.CC_AMR.getPLNCode());
		
		TlkmTsel tselXmlObj = new TlkmTsel(HTTPValues.TYPE_SUBMIT_READ_METER.getName(),param);
		
		String xml = parseTselToXML(tselXmlObj);
		trxSvc.saveNewTransaction(trxId, mapTbl.getMapId(), mapTbl.getMeterId(), Integer.parseInt(param.getUtilityCode()));
		String responseText = httpRequestPost(url, xml);
		System.out.println("Save Transaction...");
		
		System.out.print("Schedule TRX ID: "+trxId+" - "+new Timestamp(new Date().getTime()));
		System.out.println(" - Response from "+UrlList.USSD_AMR_REQUEST.getUrl()+" : "+responseText);
	}
	/*
	 * HTTP REQUEST POST METHOD
	 * this will send a request call to the url parameter
	 */
	private String httpRequestPost(String url, String xml){
		
		PostMethod post = new PostMethod(url);   
		String response = null;
	    try {
	    	System.out.println("Post Schedule job : "+formatXML(xml)+"\n to: "+url);
			Date date= new java.util.Date();
			System.out.println("Time now:"+new Timestamp(date.getTime()));
	        StringRequestEntity requestEntity = new StringRequestEntity(xml);
	        post.setRequestEntity(requestEntity);
	        
	        post.setRequestEntity(requestEntity);
	        post.setRequestHeader("Content-type", "text/xml; charset=UTF-8");
	        
	        org.apache.commons.httpclient.HttpClient httpclient = new org.apache.commons.httpclient.HttpClient();

	        int result = httpclient.executeMethod(post);
	        
	        response = post.getResponseBodyAsString();
	        
	        System.out.println(post);
	        System.out.println("Response status code: " + result);
	        System.out.println("Response body: ");
	        System.out.println(response);
	        
	    } catch (IOException e) {
	        e.printStackTrace();
	        return e.getStackTrace().toString();
	    } finally {
	        post.releaseConnection();
	    }
	    return response;
	}
	private String parseTselToXML(TlkmTsel tselXmlObj) {
		String xmlResult = null;

		StreamResult xmlStreamResult = new StreamResult(new ByteArrayOutputStream());

		try {
			JAXBContext jaxbContext = JAXBContext
					.newInstance(TlkmTsel.class);
			Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            
			jaxbMarshaller.marshal(tselXmlObj, xmlStreamResult);

			xmlResult = xmlStreamResult.getOutputStream().toString();

		} catch (JAXBException e) {
			e.printStackTrace();
			return null;
		}

		return xmlResult;
	}
	

	 public String formatXML(String xml) {

	        try {
	            final InputSource src = new InputSource(new StringReader(xml));
	            final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
	            final Boolean keepDeclaration = Boolean.valueOf(xml.startsWith("<?xml"));

	        //May need this: System.setProperty(DOMImplementationRegistry.PROPERTY,"com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl");


	            final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
	            final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
	            final LSSerializer writer = impl.createLSSerializer();

	            writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); // Set this to true if the output needs to be beautified.
	            writer.getDomConfig().setParameter("xml-declaration", keepDeclaration); // Set this to true if the declaration is needed to be outputted.

	            return writer.writeToString(document);
	        } catch (Exception e) {
	            throw new RuntimeException(e);
	        }
	 }

}
